home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
cool
/
ge_cool.lha
/
GE_COOL2.1
/
cpp
/
README
< prev
next >
Wrap
Text File
|
1992-04-13
|
9KB
|
175 lines
-*- Mode:Text -*-
Summary of CPP Macro Support
This is a summary of the defmacro language extension, its syntax and
capabilities, and examples of usage. I have composed this in an attempt to
provide a gentler introduction than that available in the man page. Note that
the following implementation details are *NOT* standard C++, but rather
extensions that we have added via an enhanced, portable preprocessor. This
preprocessor has been brought up on Sun OS, SCO XENIX, OS/2, and MVS.
There are lots of pieces to the macro facilities. Some were patterned after
LISP features such as LOOP and REST: arguments, while others such as the
parameterized types support are implementations of design papers published by
Stroustrup. Together, they provide significant language features and enhanced
power for the programmer. However, it is important to note that once any
given macro is expanded, the resulting code is plain-old vanilla C++ syntax
acceptable to any C++ translator or compiler.
The basic cpp extension mechanism utilized to implement all macro
functionality is provided by a #pragma statement. Common macros are defined
in this manner. The "defmacro" keyword follows and provides a way to execute
arbitrary filter programs (macros expanders) on code fragments. The syntax
for defmacro is:
#pragma defmacro name <file> options
or #pragma defmacro name "file" options
or #pragma defmacro name program options
where "name" is the name of the filter, <file> and "file" are the name of a
source file containing a macro definition, "program" is the name of a program
implementing a macro, and options is a series of of optional modifiers for the
defmacro explained below. The implementation of a defmacro may be either
external to the preprocessor (as in the case of files and programs) or
internal to the preprocessor. For example, the template macro implementing
parameterized types is internal to the preprocessor to provide a more
efficient, performance tuned implementation. Cpp will first search for a file
or program in the same search path as that used for include files. If a match
is not found, it then searches an internal preprocessor table. If a match is
still not found, cpp prints "Error: Cannot open macro file [xxx]", where "xxx"
is the name as it appears in the source code.
The defmacro syntax also supports a series of options. Zero or more of the
following options may be included in any order:
recursive - when present, the macro may be recursively expanded.
expanding - when present, input to the macro is expanded.
delimiter=x - the default delimiter (semicolon) is replaced with 'x'.
other - unknown options are passed as arguments to the macro
expander.
When a defmacro style macro is encountered by the preprocessor, the name and
everything until the terminating character -- including all matching and
nested levels of {} [] () <> "" '' and comments found along the way -- is
piped into the macro procedure's standard-input. The procedure's standard
output is scanned by CPP for further processing. The resulting expansion
replaces the macro input in the source.
The defmacro implementation is used to declare the MACRO (all uppercase)
keyword. This is essentially an enhanced #define syntax that supports
multiline, arbitrary length, nested macros and cpp-directives, with optional,
keyword, and body parameters. To use it include the line:
#pragma defmacro MACRO "macro" delimiter=}
thus declaring the MACRO keyword whose implementation is a cpp internal
routine named "macro". The terminating delimiter for a MACRO is the closing
brace character. The syntax for MACRO is:
MACRO name (arglist) { body }
where "name" is the name of the macro, "arglist" is a list of argument
specifiers separated by commas, and "body" is what is substituted on a call to
the macro. The "arglist" may specify positional, optional, optional keyword,
required keyword, rest and body arguments. When KEY: is specified, the macro
takes all following arguments to be keyword arguments that allow the user to
specify a particular value. Default values are support by use of an equal
sign and value and may be applied to both regular and keyword arguments. The
REST: modifier indicates that there is some number of arguments, all of which
are referenced by use of the one named identifier. An optional equal sign and
identifier will contain the number of arguments remaining. Finally, BODY:
indicates that when used, the parameter will be expanded to include all the
text within the braces after the macro call. This is useful for identifying a
section of code that implements some part of the macro or should be passed to
other nested macros. The following examples show some of the power and
flexibility of the COOL MACRO capability:
MACRO set_val (size, value=NULL, KEY: low = 0, high) {
init (size, value, low, high-low)
}
In this example, "set_val" is the name of the macro that the programmer refers
to, "size" is a required positional argument, "val" is an optional positional
argument that if not specified in a particular call has a default value of
NULL, "low" is an on optional keyword parameter, and "high" is a required
keyword parameter. In this example, the macro simple calls the function
init() with four arguments. The following show several legal invocations of
the macro along with the resulting call to the function init():
set_val (0, high=20) ----> init (0, NULL, 0, 20);
set_val (0, low=5, high=15) ----> init (0, NULL, 5, 10);
set_val (1, 2, high=25) ----> init (1, 2, 0, 25);
See the files "macro-sample.c" and "macro-sample.i" for an example usage of
this capability and the corresponding expansion.
One of the main uses of the defmacro facility is the implementation of
templates to support parameterized types. The syntax of the template grammar
is that as specified by Stroustrup in his paper "Parameterized types for C++"
in the 1988 USENIX C++ Conference Proceedings. Cpp implements this
functionality such that there will be minimal source code conversion necessary
when this feature is finally implemented in the C++ language.
A class programmer who wishes to implement a vector class object wants to make
design and implementation decisions in such a way as to facilitate a simple
and consistent interface for the application programmer, no matter what type
of thing is to be stored in the vector. In addition, replication of code for
each specific type should be avoided if at all possible. To accomplish this,
the class programmer implements a vector template, with the type selection
left to the application programmer. The following example is for a Vector
header file:
template<class Type> class Vector { // Parameterized Vector class
private:
Type* v; // Data of type pointer to Type
int size; // Size of vector object
public:
Vector (); // Empty constructor
Vector (int); // Constructor with size
Vector (Vector&); // Constructor with reference
~Vector (); // Destructor
Type& operator[](int n); // Operator[] overload for Type
Type& element (int n); // Return element of type Type
... // ... other methods ...
};
An application programmer would include this header file in the appropriate
source file. In addition, common header file must be included to provide the
#pragma statement declaring the defmacro template shown below. This must
occur before the inclusion of the Vector header file and so is done within
Vector.h if it has not already been included.
#pragma defmacro template "template" delimiter=}
An application programmer also places the following lines in his/her source
code to use the parameterized Vector class for a specific type:
DECLARE Vector<double>;
IMPLEMENT Vector<double>;
Vector<double> vs(30);
The DECLARE macro implements a series of #define preprocessor statements that
will declare and define code for a Vector of doubles. Together with the
template macro expander. A class definition with its associated methods is
created ready to be compiled, all performed invisibly to the user.
The common header file must include the #pragma statements that allow DECLARE
and IMPLEMENT to work also. They are as follows:
#pragma defmacro MACRO "macro" delimiter=} recursive
#pragma defmacro DECLARE "declare" delimiter=> recursive lines
#pragma defmacro IMPLEMENT "implement" delimiter=> recursive lines
See the files "template-sample.c" and "template-sample.i" for an example usage
of this capability and the corresponding expansion.
There are several other internal macros included with cpp that we have
experimented with. These can safely be ignored. For the interested parties
who want to delve more we refer you to the comments in the source files.